
/**
 * ClassName: ProducerConsumerTset
 * Package: chapter10_Advanced._communication
 * Description:
 *
 * 生产者和消费者，案例
 * 生产者(Productor)将产品交给店员(Clerk)，
 * 而消费者(Customer)从店员处取走产品，
 * 店员一次只能持有固定数量的产品(比如:20），
 * 如果生产者试图生产更多的产品，店员会叫生产者停一下，如果店中有空位放产品了再通知生产者继续生产；
 * 如果店中没有产品了，店员会告诉消费者等一下，如果店中有产品了再通知消费者来取走产品。
 *
 * 分析如下：
 * 1. 是否是多线程问题？是，生产者和消费者
 * 2. 是否有共享数据？是，店员（或产品）
 * 3. 是否有线程安全问题？有，因为店员（或产品）是多个线程共享的
 * 4. 如何解决线程安全问题？同步机制，synchronized
 * 5. 是否存在线程间的通信？是，因为生产者和消费者需要通信
 *
 * @Author SherryAn
 * @Create 2025/8/13 12:22
 */
package chapter10_Advanced._communication;

public class ProducerConsumerTset extends Thread{
    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Producer pro1 = new Producer(clerk);
        Customer cus1 = new Customer(clerk);

        pro1.start();
        cus1.start();
    }

}


class Clerk{ //店员
    // 产品数量
    private int product=0;
    // 添加
    public synchronized void add(){
        while (product >=20) {
            System.out.println("库存已满，等待消费者购买");
            try {
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        product++;
        System.out.println("店员添加了一个产品，目前总共有" + product + "个产品");
        notify();
    }
    // 减少
    public synchronized void reduce(){

        while (product <= 0) {
            System.out.println("库存已空，等待生产者添加");
            try {
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        product--;
        System.out.println("店员卖出了一个产品，目前剩余" + product + "个产品");
        notify();
    }
}

class Producer extends Thread{//生产者
    private Clerk clerk;
    // 此处的构造器用来创建生产者对象
    public Producer(Clerk clerk){
        this.clerk = clerk;
    }

    @Override
    public void run() {
        while (true){
            System.out.println("生产者开始生产产品...");
            try {
                sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            clerk.add();
        }
    }
}

class Customer extends Thread{//消费者
    private Clerk clerk;

    public Customer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        while (true){
            System.out.println("消费者开始消费产品...");
            clerk.reduce();
        }
    }
}
